#include "tcp_server.h"
#include "config.h"
#include "log.h"

namespace framework
{
    static framework::Logger::ptr g_logger = FRAMEWORK_LOG_NAME("system");

    static framework::ConfigVar<uint64_t>::ptr g_tcp_server_read_timeout = 
        framework::Config::Lookup("tcp_server.read_timeout", (uint64_t)(60 * 1000 * 2),  //2分钟
        "tcp server read timeout");

    //worker socket客户端工作的协程调度器
    //accept_worker 服务器socket执行接收socket连接的协程调度器
    TcpServer::TcpServer(IOManager* worker, IOManager* io_woker, IOManager* accept_worker)
    :m_worker(worker)
    ,m_ioWorker(io_woker)
    ,m_acceptWorker(accept_worker)
    ,m_recvTimeout(g_tcp_server_read_timeout->getValue())
    ,m_name("framework/1.0.0")
    ,m_isStop(true)
    {}

    TcpServer::~TcpServer()
    {
        for(auto& i : m_socks)
        {
            i->close();
        }
        m_socks.clear();
    }

    //绑定地址 调用下面的版本
    bool TcpServer::bind(Address::ptr addr, bool ssl)
    {
        std::vector<Address::ptr> addrs;
        addrs.emplace_back(addr);
        std::vector<Address::ptr> fails;
        return this->bind(addrs, fails, ssl);
    }

    //绑定地址数组
    bool TcpServer::bind(const std::vector<Address::ptr>& addrs
                        ,std::vector<Address::ptr>& fails
                        ,bool ssl)
    {
        m_ssl = ssl;
        for(auto& addr: addrs)
        {
            Socket::ptr sock = ssl ? SSLSocket::CreateTCP(addr) : Socket::CreateTCP(addr);
            if(!sock->bind(addr))
            {
                FRAMEWORK_LOG_ERROR(g_logger) << "bind fail errno="
                    << errno << " errstr=" << strerror(errno)
                    << " addr=[" << addr->toString() << "]";
                fails.push_back(addr);
                continue;
            }
            if(!sock->listen())
            {
                FRAMEWORK_LOG_ERROR(g_logger) << "listen fail errno="
                    << errno << " errstr=" << strerror(errno)
                    << " addr=[" << addr->toString() << "]";
                fails.push_back(addr);
                continue;
            }
            m_socks.emplace_back(sock);
        }
        
        //如果有绑定或者监听失败的地址
        if(!fails.empty())
        {
            m_socks.clear();
            return false;
        }

        for(auto& i : m_socks) {
            FRAMEWORK_LOG_INFO(g_logger) << "type=" << m_type
                << " name=" << m_name
                << " ssl=" << m_ssl
                << " server bind success: " << *i;
        }
        return true;
    }

    bool TcpServer::loadCertificates(const std::string& cert_file, const std::string& key_file)
    {
        return false;
    }

    //启动服务(启动accept)
    bool TcpServer::start()
    {
        if(!m_isStop)
        {
            return true;
        }

        m_isStop = false;
        for(auto& sock : m_socks) 
        {
            m_acceptWorker->schedule(std::bind(&TcpServer::startAccept,
            shared_from_this(), sock));
        }
        return true;
    }

    //停止服务
    void TcpServer::stop()
    {
        m_isStop = true;
        auto self = shared_from_this();

        //添加协程，取消sock上的所有事件并关闭sock
        m_acceptWorker->schedule([this, self](){
            for(auto& sock : m_socks)
            {
                sock->cancelAll();
                sock->close();
            }
            m_socks.clear();
        });
    }

    //设置TcpServerConf
    void TcpServer::setConf(const TcpServerConf& v)
    {
        m_conf.reset(new TcpServerConf(v));
    }

    std::string TcpServer::toString(const std::string& prefix)
    {
        return prefix;
    }


    //处理新连接的Socket类
    void TcpServer::handleClient(Socket::ptr client)
    {
        FRAMEWORK_LOG_INFO(g_logger) << "handleClient: " << *client;
    }

    //开始接受连接
    void TcpServer::startAccept(Socket::ptr sock)
    {
        while(!m_isStop)
        {
            Socket::ptr client = sock->accept();
            if(client)
            {
                client->setRecvTimeout(m_recvTimeout);
                m_ioWorker->schedule(std::bind(&TcpServer::handleClient,
                    shared_from_this(), client));
            }
            else
            {
                FRAMEWORK_LOG_ERROR(g_logger) << "accept errno=" << errno
                    << " errstr=" << strerror(errno);
            }
        }
    }


}//framework